/***************************************************************************************
 * Copyright 2020 Infineon Technologies AG ( www.infineon.com ).                       *
 * All rights reserved.                                                                *
 *                                                                                     *
 * Licensed  Material-Property of Infineon Technologies AG.                            *
 * This software is made available solely pursuant to the terms of Infineon            *
 * Technologies AG agreement which governs its use. This code and the information      *
 * contained in it are proprietary and confidential to Infineon Technologies AG.       *
 * No person is allowed to copy, reprint, reproduce or publish any part of this code,  *
 * nor disclose its contents to others, nor make any use of it, nor allow or assist    *
 * others to make any use of it - unless by prior Written express authorization of     *
 * Infineon Technologies AG and then only to the extent authorized.                    *
 *                                                                                     *
 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,            *
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,           *
 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE DISCLAIMED.  IN NO       *
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,     *
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,                 *
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;         *
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY             *
 * WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR            *
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF              *
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                          *
 *                                                                                     *
 ***************************************************************************************/
/**
 * @file   host_auth.c
 * @date   June, 2020
 * @brief  Implementation of host authentication routine
 */


#include "helper.h"
#include "auths_api.h"
#include "auths_config.h"
#include "auths_status.h"
#include "crypto_lib.h"

#include "i2c_bus_command.h"

extern AuthS_Capability auths_capability;

#define  POLL_HRREQ1   (1)  //Set "1" to poll for HRREQ1. Set "0" for fixed delay.

/**
* @brief Send HRREQ and HRRES to device to get random number
* @param ub_nonceA Nounce A read from device
*/
uint16_t GetRandomNumber(uint8_t *ub_nonceA){
	uint16_t ret = APP_HA_INIT;

	if (ub_nonceA == NULL) {		
		return APP_HA_E_INPUT;
	}

	// Request for random number from Authenticate S

	if(auths_capability.active_interface==I2C){
		ret = i2c_bus_command_HRREQ(auths_capability.interface.i2c.device_address);
		if (ret != INF_I2C_SUCCESS) {		
			return APP_HA_E_HRREQ;
		}
		
		//Fixed wait for RNG completion
		//todo System porting required: implements delay according to platform.
		delay_us(200); //Max RNGT is 60us

		// Get random number
		ret = i2c_bus_command_HRRES(auths_capability.interface.i2c.device_address, ub_nonceA);
		if (ret != INF_I2C_SUCCESS) {
			return APP_HA_E_HRRES;
		}
	}

	return ret;

}

uint16_t check_MAC_done(void){
#if (POLL_HRREQ1==1)
	uint8_t busy=1;
	uint8_t retry = 50;
	uint8_t timeout=100;
	uint16_t regaddr = AUTHS_SFR_BUSY_STS;
	uint8_t rd_data=0x0;
	uint16_t ret = APP_HA_INIT;

	// wait for MAC done
	do{
		ret = Intf_ReadRegister(regaddr, &rd_data, 1);
		if (SDK_INTERFACE_SUCCESS != ret ) {
			rd_data=(0x1<< BIT_AUTH_MAC_BUSY) | (0x1<<BIT_RANDOM_NUM_BUSY);//default busy if unable to read actual register value
			if(retry==0){
				return ret;
			}
		}else{
			busy = (rd_data >> BIT_AUTH_MAC_BUSY) & 0x01;
		}
		timeout--;
		retry--;
		if (timeout == 0) {
			return APP_HA_MAC_BUSY;
		}
	}while(busy == 1);
#else
	delay_ms(3);
#endif

	return APP_HA_MAC_DONE;

}

/**
* @brief Perform host authentication
*/
#if (HOST_AUTHENTICATION_FEATURE_SUPPORTED==1)
uint16_t auths_exe_host_authentication(){
	uint8_t ub_nonceA[MAC_BYTE_LEN];
	uint8_t ub_nonceB[MAC_BYTE_LEN];
	uint8_t ub_tagA[MAC_BYTE_LEN];
	uint8_t ub_tagB[MAC_BYTE_LEN];
	uint16_t ret = APP_HA_INIT;

	//Check if device has host auth support
	if(auths_get_ifx_config(HOSTAUTH_CONFIG)== APP_HA_DISABLE){
		return APP_HA_DISABLE;
	}

	ret = GetRandomNumber(ub_nonceA);
	if (APP_HA_SUCCESS != ret) {
		return APP_HA_Get_NOUNCEA_FAILED;		
	}
	
	rand_byte(ub_nonceB, MAC_BYTE_LEN);

	if(auths_capability.active_interface==I2C){
		ret = i2c_bus_command_DRRES(auths_capability.interface.i2c.device_address, ub_nonceB);
		if (INF_I2C_SUCCESS != ret) {
		return APP_HA_E_DRRES;		
		}
		
		ret = HA_GenerateTagA(ub_tagA, ub_nonceA, ub_nonceB, MAC_GROUP_0);
		if (APP_HA_SUCCESS != ret) {
			return APP_HA_E_TAGA;
		}

		ret = i2c_bus_command_HREQ1(auths_capability.interface.i2c.device_address, ub_tagA);
		if (INF_I2C_SUCCESS != ret) {
			return APP_HA_E_HREQ1;
		}

	//Required extra time required for HRREQ1
		ret = check_MAC_done();
	    if(APP_HA_MAC_DONE != ret){
			return ret;
		}

		ret = i2c_bus_command_DRES1(auths_capability.interface.i2c.device_address, ub_tagB);
		if (INF_I2C_SUCCESS != ret) {
			return APP_HA_E_DRES1;
		}

	}
#endif


	if (APP_HA_SUCCESS != VerifyTagB(ub_tagB, ub_nonceA, ub_nonceB, MAC_GROUP_0)) {
		return APP_HA_E_TAGB;
	} else{
		auths_capability.host_auth_done=host_auth_done;
		return APP_HA_SUCCESS;
	}
}

